use mongo_service::user::{TokenGenerator, TokenMiddleware};
use mongodb::Client;
use tide::{convert::json, Middleware, Next, Request, Result};

pub struct ShowErrorMiddleware;

#[tide::utils::async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for ShowErrorMiddleware {
    async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> Result {
        let mut res = next.run(req).await;
        if let Some(err) = res.error() {
            let msg = err.to_string();
            res.set_body(json!({ "error": msg }));
        }
        Ok(res)
    }
}

#[async_std::main]
async fn main() -> tide::Result<()> {
    let client = Client::with_uri_str("mongodb://localhost:27017").await?;
    let token_generator = TokenGenerator {
        secret: std::env::var("TOKEN_SECRET")
            .expect("TOKEN_SECRET env var is not set.")
            .into_bytes(),
        ttl: chrono::Duration::days(1).num_seconds() as u32,
    };
    let mut app = tide::new();
    app.with(ShowErrorMiddleware);
    app.with(TokenMiddleware {
        public_readable_paths: vec![],
        public_writable_paths: vec!["/user/login".to_string(), "/user/register".to_string()],
        token_generator: token_generator.clone(),
        users: client.database("account").collection("users"),
    });
    app.with(mongo_service::role::RoleMiddleware {
        roles: client.database("database").collection("roles"),
    });
    app.at("/user").nest(mongo_service::user(
        client.database("account").collection("users"),
        token_generator,
    ));
    app.at("/data").nest(mongo_service::data(client.database("database")));
    app.listen("127.0.0.1:8080").await?;
    Ok(())
}
